# Написать обработчик прерываний по таймеру handler:, который переключает контекст выполнения между двумя задачами, а после истечения тайм-аута — выполняет третью.
# Написать также подпрограмму init:, которой передаётся 6 параметров (через регистры a*):
#    Адрес первой задачи
#    Продолжительность такта (квант работы) первой задачи
#    Адрес второй задачи
#    Продолжительность такта (квант работы) второй задачи
#    Адрес завершающей задачи
#    Время, по истечении которого надо запустить завершающую задачу 
# Требования и допущения:
#    Задачи используют только регистры типа a* и не используют стек, для простоты сохранения контекста
#    Алгоритм работы обработчика: переключить контекст на другую задачу (включая uepc), выставить таймер равным кванту работы этой задачи; когда придёт время завершения,
#	таймер не выставлять, а вернуться сразу в завершающую задачу
#    Первая и вторая «задачи» в данном задании — это бесконечно работающие фрагменты кода, начинающиеся с определённого адреса;
#	третья — фрагмент кода, вызывающий по окончании работы ecall 10.
#/!\ Значения очень сильно отличаются от запуска к запуску и сильно зависят от производительности компьютера (привет Java?),
#	так что если одно число результата примерно в два раза больше другого, то и ладно.
# Вводится три числа:
#	квант работы первой задачи в миллисекундах,
#	квант работы первой второй в миллисекундах,
#	общее время работы в миллисекундах 

.eqv    TIME    0xFFFF0018
.eqv    TIMECMP 0xFFFF0020

.text
.globl  main
main:   li      a7 5
        ecall
        mv      a1 a0
        li      a7 5
        ecall
        mv      a3 a0
        li      a7 5
        ecall
        mv      a5 a0

        la      a0 TaskA
        la      a2 TaskB
        la      a4 Ending
        jal     init
        
        lw      a0 0xffff0018
        addi    a0 a0 1
        sw      a0 0xffff0020 a1
        la      a0 handler
        csrw    a0 utvec
        csrwi   uie 0x10
        csrwi   ustatus 1

        b       TaskA

.data
TaskAC: .word   0
TaskBC: .word   0
.text
TaskA:  mv      a0 zero
TaskAL: addi    a0 a0 1
        sw      a0 TaskAC a1
        b       TaskAL

TaskB:  mv      a0 zero
TaskBL: addi    a0 a0 1
        sw      a0 TaskBC a1
        b       TaskBL

Ending: lw      a0 TaskAC
        li      a7 1
        ecall
        li      a0 '\n'
        li      a7 11
        ecall
        lw      a0 TaskBC
        li      a7 1
        ecall
        li      a0 '\n'
        li      a7 11
        ecall
        li      a7 10
        ecall


.data
addr_A:	.word	0
time_A:	.word	0
addr_B:	.word	0
time_B:	.word	0
addr_R:	.word	0
time_R:	.word	0
h_a0:	.word	0
h_a1:	.word	0
cur_t:	.word	0

.text
init:
	addi    sp,  sp, -4
        sw      ra,  (sp)
	sw      a0 addr_A t0
	sw      a1 time_A t0
	sw      a2 addr_B t0
	sw      a3 time_B t0
	sw      a4 addr_R t0
	lw      t0 TIME					# Время переключения на последнюю задачу установим от текущего
        add	a5 a5 t0
	sw      a5 time_R t0 
	lw      ra, (sp)
        addi    sp, sp, 4
	ret	


handler:
	csrw	t0 uscratch
	lw      t0 time_R				# Если время работы первых двух задач вышло переключаемся на последнюю
	lw	t1 TIME
	bgt	t1 t0 task_end
	
	lw	t0 h_a0					# Переключаем контекст на другую задачу
	sw	a0 h_a0 t1
	mv	a0 t0
	lw	t0 h_a1
	sw	a1 h_a1 t1
	mv	a1 t0
	
	lw	t0 cur_t				# Проверим какая задача в работе
	beqz	t0 task_a
	
	csrr    t0 uepc					# Работает задача B, переключаемся на A
	sw	t0 addr_B t1
	lw	t0 addr_A
	csrw    t0 uepc
	sw	zero cur_t t1
	lw      t0 time_A
	lw	t1 TIME
	add	t0 t0 t1
	sw	t0 TIMECMP t1
	b exit
	
task_a:
	csrr    t0 uepc					# Работает задача A, переключаемся на B
	sw	t0 addr_A t1
	lw	t0 addr_B
	csrw    t0 uepc
	li	t0 1
	sw	t0 cur_t t1
	lw      t0 time_B
	lw	t1 TIME
	add	t0 t0 t1
	sw	t0 TIMECMP t1
	b exit
	
task_end:
	lw	t0 addr_R
	csrw    t0 uepc        
exit:   csrr    t0 uscratch     			# восстановим t0, а t1 не будем))
        uret
